//call 和apply 最常见的用途是改变函数内部的this 指向，我们来看个例子：
var obj1 = {
    name: 'sven'
};

var obj2 = {
    name: 'anne'
};

window.name = 'window';

var getName = function(){
    console.log ( this.name );
};

getName(); // 输出: window
getName.call( obj1 ); // 输出: sven
getName.call( obj2 ); // 输出: anne


Function.prototype.bind = function( context ){
    var self = this; // 保存原函数
    return function(){ // 返回一个新的函数
        return self.apply( context, arguments ); // 执行新的函数的时候，会把之前传入的context当作新函数体内的this
    }
};

var obj = {
    name: 'sven'
};

var func = function(){
    console.log ( this.name ); // 输出：sven
}.bind( obj);

func();

//通常我们还会把它实现得稍微复杂一点，使得可以往func函数中预先填入一些参数：”

Function.prototype.bind = function(){
    var self = this, // 保存原函数
    context = [].shift.call( arguments ), // 需要绑定的this 上下文
    args = [].slice.call( arguments ); // 剩余的参数转成数组
    return function(){ // 返回一个新的函数
        return self.apply( context, [].concat.call( args, [].slice.call( arguments ) ) );
            // 执行新的函数的时候，会把之前传入的context 当作新函数体内的this
            // 并且组合两次分别传入的参数，作为新函数的参数
    }
};



var obj = {
    name: 'sven'
};

var func = function( a, b, c, d ){
    console.log ( this.name ); // 输出：sven
    console.log ( [ a, b, c, d ] ) // 输出：[ 1, 2, 3, 4 ]
}.bind( obj, 1, 2 );

func( 3, 4 );

//借用方法的第一种场景是“借用构造函数”，通过这种技术，可以实现一些类似继承的效果：
var A = function( name ){
    this.name = name;
};

var B = function(){
    A.apply( this, arguments );
};

B.prototype.getName = function(){
    return this.name;
};

var b = new B( 'sven' );
console.log( b.getName() ); // 输出： 'sven'

//通常会借用Array.prototype.push：
(function(){
    Array.prototype.push.call( arguments, 3 );
    console.log ( arguments ); // 输出[1,2,3]
})( 1, 2 );


//看看V8 引擎中的具体实现：
function ArrayPush() {
    var n = TO_UINT32( this.length ); // 被push 的对象的length
    var m = %_ArgumentsLength(); // push 的参数个数
    for (var i = 0; i < m; i++) {
        this[ i + n ] = %_Arguments( i ); // 复制元素 (1)
    }
    this.length = n + m; // 修正length 属性的值 (2)
    return this.length;
};


//通过这段代码可以看到，Array.prototype.push实际上是一个属性复制的过程，把参数按照下标依次添加到被push的对象上面，顺便修改了这个对象的length属性。至于被修改的对象是谁，到底是数组还是类数组对象，这一点并不重要。
//由此可以推断，我们可以把“任意”对象传入Array.prototype.push：

var a = {};
Array.prototype.push.call( a, 'first' );

console.log ( a.length );    // 输出：1
console.log ( a[ 0 ] );    // first”


//可以借用Array.prototype.push方法的对象还要满足以下两个条件，从ArrayPush函数的(1)处和(2)处也可以猜到，这个对象至少还要满足：

//对象本身要可以存取属性；
//对象的length属性可读写。”

